package com.wnxy.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.hash.BloomFilter;
import com.wnxy.admin.common.handler.*;
import com.wnxy.admin.common.util.OrderUtil;
import com.wnxy.admin.common.util.SettlementUtil;
import com.wnxy.admin.dto.OrderDto;
import com.wnxy.admin.dto.VirtualPayDto;
import com.wnxy.admin.entity.*;
import com.wnxy.admin.mapper.*;
import com.wnxy.admin.service.IChargingCardService;
import com.wnxy.admin.service.IChargingPileService;
import com.wnxy.admin.service.ICouponService;
import com.wnxy.admin.service.IOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.Map;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author (^･ｪ･^)Cat~
 * @since 2023-12-02
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private final OrderMapper orderMapper;
    private final CustomerMapper customerMapper;
    private final ReservationMapper reservationMapper;
    private final ChargingCardMapper chargingCardMapper;
    private final ChargingStationMapper chargingStationMapper;
    private final ChargingPileMapper chargingPileMapper;
    private final RedisTemplate redisTemplate;
    private final SettlementUtil settlementUtil;
    private final ICouponService couponServiceImpl;
    private final IChargingCardService chargingCardServiceImpl;
    private final OrderUtil orderUtil;
    private final IChargingPileService chargingPileServiceImpl;
    private final TransactionMapper transactionMapper;
    private final BloomFilter<String> bloomFilter;
    public OrderServiceImpl(OrderMapper orderMapper, CustomerMapper customerMapper, ReservationMapper reservationMapper, ChargingCardMapper chargingCardMapper, ChargingStationMapper chargingStationMapper, ChargingPileMapper chargingPileMapper, RedisTemplate redisTemplate, SettlementUtil settlementUtil, ICouponService couponServiceImpl, IChargingCardService chargingCardServiceImpl, OrderUtil orderUtil, IChargingPileService chargingPileServiceImpl, TransactionMapper transactionMapper, BloomFilter<String> bloomFilter){
        this.orderMapper = orderMapper;
        this.customerMapper = customerMapper;
        this.reservationMapper = reservationMapper;
        this.chargingCardMapper = chargingCardMapper;
        this.chargingStationMapper = chargingStationMapper;
        this.chargingPileMapper = chargingPileMapper;
        this.redisTemplate = redisTemplate;
        this.settlementUtil = settlementUtil;
        this.couponServiceImpl = couponServiceImpl;
        this.chargingCardServiceImpl = chargingCardServiceImpl;
        this.orderUtil = orderUtil;
        this.chargingPileServiceImpl = chargingPileServiceImpl;
        this.transactionMapper = transactionMapper;
        this.bloomFilter = bloomFilter;
    }

    @Override
    public Order queryOrderDetail(Long orderId) {
        Order order = orderMapper.selectOne(Wrappers
                .lambdaQuery(Order.class)
                .eq(Order::getOrderId, orderId));
        return order;
    }

    /* Model:订单生成业务 */
    @Transactional
    @Override
    public void saveOrder(Order order) {
        // 1-获取客户信息
        Customer customer = customerMapper.selectOne(Wrappers.lambdaQuery(Customer.class)
                .eq(Customer::getId, order.getCustomerId()));
        if (customer == null || customer.getAccount().isEmpty()) {
            throw new BusinessException(BusinessEnum.ORDER_CREATE_FAIL);
        }

        // 2-更新预约订单【state - 已成功】
        if (customer != null && customer.getService() == OrderStatusEnum.SERVICE_RESERVATION.getCode()) {
            Reservation reservation = reservationMapper.selectOne(Wrappers.lambdaQuery(Reservation.class)
                    .eq(Reservation::getCustomerId, customer.getId())
                    .eq(Reservation::getState, ReservationEnum.APPOINTMENT_IN_PROGRESS.getCode()));

            if (reservation != null) {
                orderUtil.done(reservation);

                /*customer.setService(OrderStatusEnum.SERVICE_LEISURE.getCode());
                customerMapper.updateById(customer);*/
            }
        }

        // 3-获取电桩编号PileId/充电站ID [ChargingCard实体]
        ChargingPile chargingPile = chargingPileMapper.selectOne(Wrappers.lambdaQuery(ChargingPile.class)
                .eq(ChargingPile::getChargingPileNumber, order.getChargingPileNumber()));

        ChargingCard chargingCard = chargingCardMapper.selectOne(Wrappers.lambdaQuery(ChargingCard.class)
                .eq(ChargingCard::getChargingCardNumber, order.getPaymentMethod()));
        if (chargingCard.getChargingStationId() != 0) {
            throw new BusinessException(BusinessEnum.CREATE_ORDER_FAIL);
        }
        chargingCard.setChargingStationId(chargingPile.getChargingStationId());
        chargingCardMapper.updateById(chargingCard);

        // 4-获取ChargingStation充电站 【station_name/充电ID/】
        ChargingStation chargingStation = chargingStationMapper.selectOne(Wrappers.lambdaQuery(ChargingStation.class)
                .eq(ChargingStation::getId, chargingCard.getChargingStationId()));

        // 5-Snowflake生成雪花ID + 获取NOW() 【Order】
        Snowflake snowflake = IdUtil.getSnowflake(2, 2);
        Long orderId = snowflake.nextId();

        // 6-Order订单详情
        order.setOrderId(orderId);
        order.setCreateTime(new Date());

        order.setCustomerId(customer.getId());
        order.setCustomerName(customer.getName());
        order.setCustomerPhone(customer.getPhone());

        order.setChargingStationId(chargingPile.getChargingStationId());
        /*order.setPaymentMethod(chargingCard.getChargingCardNumber());  *//* RD卡编号 */

        order.setChargingStationName(chargingStation.getChargingStationName());
        order.setChargingId(chargingStation.getBillingRuleId());  /* Tip:暂用于Rule绑定 */

        order.setChargingPileNumber(chargingPile.getChargingPileNumber());

        order.setTransactionStatus(OrderStatusEnum.IS_CHARGING.getCode());

        // 7-订单创建 + 切换Plie电桩状态
        orderMapper.insert(order);
        chargingPileServiceImpl.switchPileState(order.getChargingPileNumber(), ChargingPileStateEnum.PIE_WORKING.getCode());

        // 8-Redis(id)
        Order dbOrder = orderMapper.selectOne(Wrappers.lambdaQuery(Order.class).eq(Order::getOrderId, order.getOrderId()));
        putOrder4Redis(dbOrder.getPaymentMethod(), dbOrder);
    }

    /* MQTT订阅式触发 */
    @Override
    public void saveOrderDto(OrderDto orderDto) {
        // 0-通过MQTT获取 [cardId / customerId / paymentMethod[cardNumber] / cardId绑chargingPileNumber]
        Order order = orderUtil.generateOrder(orderDto);

        // 1-订单生成业务流
        saveOrder(order);
    }

    /* Model2: 内部支付业务 - 支付 */
    @Transactional
    @Override
    public void cardPay(Long cardId) {
        // 0-获取操作对象Order
        ChargingCard chargingCard = chargingCardServiceImpl.queryChargingCardDetail(cardId);
        Order order = getOrder4Redis(chargingCard.getChargingCardNumber());
        if (order == null || order.getTransactionStatus() == OrderStatusEnum.SUCCESS_PAY.getCode()) {
            throw new BusinessException(BusinessEnum.ORDER_NO_FIND);
        }
        BigDecimal totalAmount = order.getAmount();

        // 4-扣取充值卡余额(同时获取NOW())
        /*ChargingCard chargingCard = chargingCardMapper.selectOne(Wrappers.lambdaQuery(ChargingCard.class)
                .eq(ChargingCard::getCustomerId, order.getCustomerId()));*/
        if (chargingCard.getChargingCardMoney().compareTo(totalAmount) < 0) {
            /*transactionStatus = OrderStatusEnum.NO_PAY.getCode();*/
            throw new BusinessException(BusinessEnum.ORDER_CARD_PAY_FAIL);
        }
        BigDecimal balance = chargingCard.getChargingCardMoney().subtract(totalAmount);
        chargingCard.setChargingCardMoney(balance);
        chargingCard.setChargingStationId(0L);
        chargingCardMapper.updateById(chargingCard);
        Integer transactionStatus = OrderStatusEnum.SUCCESS_PAY.getCode();

        // 6-根据业务流,获取Order【transaction_status - 待支付3 / 已结束1】
        order.setTransactionStatus(transactionStatus);

        // 7-更新订单
        Date endTime = new Date();
        order.setEndTime(endTime);
        order.setTransactionStatus(transactionStatus);
        orderMapper.updateById(order);
        putOrder4Redis(order.getPaymentMethod(), order);

        // 8-走流水Transaction
        Transaction transaction = new Transaction();

        BeanUtil.copyProperties(order, transaction);

        Snowflake snowflake = IdUtil.getSnowflake(2, 2);
        Long transactionId = snowflake.nextId();

        transaction.setTransactionId(transactionId);
        transaction.setVersion(0);
        transaction.setTransactionTime(endTime);
        transaction.setTransactionType(order.getPaymentMethod());
        transaction.setPaymentMethod("RD-Card");
        transaction.setChargingPileNumber(order.getChargingStationName());
        transactionMapper.insert(transaction);

        /*// 9-释放CardId状态 [空闲-OL]
        chargingCardServiceImpl.editChargingStationId(order.getCustomerId(), 0L);*/
    }

    /* Model1: 内部支付业务 - 结算  */
    @Transactional
    public void settleAccounts(String cardNumber) {
        // 0-获取操作对象Order
        Order order = getOrderByCardNumber(cardNumber);
        if (order == null) {
            throw new BusinessException(BusinessEnum.ORDER_NO_FIND);
        }

        // 1-结算: ①充电时长 / ②充电电量 / ③金额于计费规则【CardNumber】
        VirtualPayDto virtualPayDto = settlementUtil.chargeSettlement(order.getPaymentMethod());

        // 2-获取优惠券Coupon -> 随缘满减优惠
        Coupon coupon = couponServiceImpl.chooseCoupon(order.getCustomerId());

        // 3-合计总金额
        BigDecimal totalAmount = virtualPayDto.getAmount();
        if (coupon != null) {
            if (coupon.getAmount().compareTo(BigDecimal.ZERO) > 0) {
                order.setChargeType(order.getChargeType() + " -" + coupon.getAmount());  // -coupon.getAmount()
            } else {
                order.setChargeType(order.getChargeType() + " *" + coupon.getDiscount());  // -coupon.getDiscount()
            }
            BigDecimal discountAmount = virtualPayDto.getAmount()
                    .subtract(coupon.getAmount())
                    .multiply(coupon.getDiscount());
            discountAmount = discountAmount.setScale(2, RoundingMode.HALF_UP);

            // 如若,折扣后金额小于0,则使用原始金额
            totalAmount = discountAmount.compareTo(BigDecimal.ZERO) < 0 ? totalAmount : discountAmount;

            virtualPayDto.setAmount(totalAmount);
        }
        order.setAmount(totalAmount);

        // 5-核销优惠券[待办->寄]
        couponServiceImpl.removeCouponByCustomerId(order.getCustomerId(), coupon.getCouponId());

        // 6-根据业务流,获取Order【transaction_status -> 待支付3】
        if (order.getTransactionStatus() == OrderStatusEnum.IS_CHARGING.getCode()) {
            order.setTransactionStatus(OrderStatusEnum.NO_PAY.getCode());
            // 7-更新订单
            orderMapper.updateById(order);

            Order tempOrder = orderMapper.selectById(order.getOrderId());
            putOrder4Redis(order.getPaymentMethod(), tempOrder);

            // 8-释放Plie电桩状态
            chargingPileServiceImpl.switchPileState(order.getChargingPileNumber(), ChargingPileStateEnum.PIE_DEFAULT.getCode());
        }
    }

    @Transactional
    @Override
    public void editOrder(OrderDto orderDto) {
        // 0-预CardNumber未能回传
        if (orderDto.getCardNumber().equals("")) {
            ChargingCard chargingCard = chargingCardServiceImpl.queryChargingCardDetail(orderDto.getCardId());
            orderDto.setCardNumber(chargingCard.getChargingCardNumber());
        }

        // 1-获取Redis中的业务Order
        Order order = getOrder4Redis(orderDto.getCardNumber());
        if (order == null) {
            throw new BusinessException(BusinessEnum.ORDER_NO_FIND);
            // TODO: 2023-12-6 可进一步处理
        }

        // 2-校验是否为业务订单
        if (orderDto.getChargeDuration() > 0 && orderDto.getChargingPileNumber().equals(order.getChargingPileNumber())) {
               order.setEndTime(new Date());
               order.setChargeAmount(orderDto.getChargeAmount());
               order.setChargeDuration(orderDto.getChargeDuration());
        }

        // 3-初步结算
        orderMapper.updateById(order);
        putOrder4Redis(order.getPaymentMethod() , order);
        settleAccounts(order.getPaymentMethod());
    }

    @Override
    public void drop(Long orderId, String code) {
        if (!code.equals(String.valueOf(OrderStatusEnum.ORDER_DROP_CODE.getCode()))) {
            throw new BusinessException(BusinessEnum.ORDER_DROP_FAIL);
        }
        releaseState4Order(orderId);
        orderMapper.deleteById(orderId);
    }


    private Order getOrderByCardNumber(String cardNumber){
        Order order = getOrder4Redis(cardNumber);

        if (order == null) {
            orderMapper.selectOne(Wrappers.lambdaQuery(Order.class)
                    .eq(Order::getPaymentMethod, cardNumber)
                    .eq(Order::getTransactionStatus, OrderStatusEnum.NO_PAY));
        }

        return order;
    }

    private void putOrder4Redis(String cardNumber, Order order) {
        HashOperations<String, String, Order> hashOperations = redisTemplate.opsForHash();
        hashOperations.put("Order", order.getPaymentMethod(), order);
    }

    private Order getOrder4Redis(String cardNumber) {
        HashOperations<String, String, Order> hashOperations = redisTemplate.opsForHash();
        Map<String, Order> entries = hashOperations.entries("Order");
        System.out.println("Entries: " + entries);

        Object tempOrder = entries.get(cardNumber);
        Order order = new Order();
        BeanUtil.copyProperties(tempOrder, order);
        return order;
    }


    private void releaseState4Order(Long orderId) {
        Order order = orderMapper.selectById(orderId);
        if (order.getTransactionStatus() == OrderStatusEnum.IS_CHARGING.getCode()) {
           chargingCardServiceImpl.editChargingStationId(order.getCustomerId(),
                   Long.valueOf(OrderStatusEnum.SERVICE_LEISURE.getCode()));

           chargingPileServiceImpl.switchPileState(order.getChargingPileNumber(), ChargingPileStateEnum.PIE_DEFAULT.getCode());
       }
        if (order.getTransactionStatus() == OrderStatusEnum.NO_PAY.getCode()) {
            chargingCardServiceImpl.editChargingStationId(order.getCustomerId(),
                    Long.valueOf(OrderStatusEnum.SERVICE_LEISURE.getCode()));
        }

    }
}